package com.jay.taskflow

import android.text.TextUtils
import android.util.Log
import androidx.core.util.lruCache
import com.jay.loglibrary.BuildConfig
import java.lang.StringBuilder
import java.util.*
import kotlin.collections.HashMap
import kotlin.collections.LinkedHashSet

/**
 * taskflow 运行时的任务调度器
 *
 * 1.根据task的属性以不用的策略(线程，同步，延迟)调度任务
 * 2.校验 依赖树中是否存在环形依赖
 * 3.校验依赖树中是否存在taskId相同的任务
 * 4.统计所有的task的运行时信息(线程，状态，开始执行时间，耗时时间,是否是阻塞任务)用于log输出
 */
internal object TaskRuntime {
  //通过addBlockTask (String name)指定启动阶段 需要阻塞完成的任务，只有当blockTasksId当中的任务都执行完了
  //才会释放application的阻塞，才会拉起launchActivity
  val blockTasksId:MutableList<String> = mutableListOf()
  //如果blockTasksId集合中的任务还没有完成，那么在主线程中执行的任务 会被添加到waitingTasks集合里面去
  //目的是为了优先保证 阻塞任务的优先完成，尽可能早的拉起launchActivity
  val waitingTasks:MutableList<Task> =  mutableListOf()
  //记录下 启动阶段所有任务的运行时信息key 是taskId
  val taskRuntimeInfos :MutableMap<String,TaskRuntimeInfo> = HashMap()

  val taskComparator = Comparator<Task>{ task1, task2 -> Util.compareTask(task1, task2)}

    @JvmStatic
   fun addBlockTask(id:String){
     if(!TextUtils.isEmpty(id)){
         blockTasksId.add(id)
     }
   }
    @JvmStatic
   fun  addBlockTasks(vararg  ids:String){
       if(ids.isNotEmpty()){
           for(id in ids){
               addBlockTask(id)
           }
       }
   }

    @JvmStatic
   fun removeBlockTask(id:String){
       blockTasksId.remove(id)
   }

    @JvmStatic
   fun hasBlockTasks():Boolean{
       return  blockTasksId.iterator().hasNext()
   }
    @JvmStatic
    fun hasWaitingTasks():Boolean{
      return waitingTasks.iterator().hasNext()
    }
    @JvmStatic
    fun setThreadName(task: Task,threadName:String?){
        val taskRuntimeInfo=getTaskRuntimeInfo(task.id)
        taskRuntimeInfo?.threadName=threadName
    }
    @JvmStatic
    fun  setStateInfo(task: Task){
        val taskRuntimeInfo= getTaskRuntimeInfo(task.id)
        taskRuntimeInfo?.setStateTime(task.state,System.currentTimeMillis())
    }
    @JvmStatic
    fun  getTaskRuntimeInfo(id:String):TaskRuntimeInfo?{
        return taskRuntimeInfos.get(id)
    }

    //根据task的属性以不用的策略 调度task
    @JvmStatic
    fun  executeTask(task: Task){
        if(task.isAsyncTask){
//          HiExecutor.execute(runnable = task)
        }else{
            //else里面的都是在主线程执行的
            //延迟任务，但是如果这个延迟任务 它存在着后置任务 A(延迟任务) -->B-->C (Block task)
            if(task.delayMills>9&&!hasBlockBehindTask(task)){
                MainHandler.postDelay(task.delayMills,task)
                return
            }
            if(!hasBlockTasks()){
                task.run()
            }else{
                addWaitingTask(task)
            }
        }
    }

    //把一个主线程上需要执行的任务，但有不影响launchActivity的启动，添加到等待队列
    private fun  addWaitingTask(task: Task){
        if(!waitingTasks.contains(task)){
            waitingTasks.add(task)
        }
    }
    //检测一个延迟任务 是否存在着后置的阻塞任务(就是等他们都执行完了，才会释放application的阻塞，才会拉起launchActivity)
    private fun  hasBlockBehindTask(task:Task):Boolean {
        if(task is Project.CriticalTask){
          return false
        }
        val behindTasks = task.behindTasks
        for(behindTask in behindTasks){
            //需要判断一个task 是不是阻塞任务，blockTaskId--
            val behindTaskInfo= getTaskRuntimeInfo(behindTask.id)
            return if(behindTaskInfo!=null&&behindTaskInfo.isBlockTask){
                 true
            }else{
                hasBlockBehindTask(behindTask)
            }
        }
        return false
    }

    /**
     * 校验 依赖树中是否存在环形依赖校验，依赖树中是否存在taskId相同的任务 初始化task对应taskRuntimeInfo
     * 遍历依赖树 完成启动前的检查和初始化
     */
    @JvmStatic
    fun traversalDependencyThreeAndInit(task: Task){
        val traversalVisitor= linkedSetOf<Task>()
        traversalVisitor.add(task)
        innerTraversakDependencyTreeAndInit(task,traversalVisitor)
        val iterator= blockTasksId.iterator()
        while (iterator.hasNext()){
            val taskId=iterator.next()
            //检查这个阻塞任务 是否存在依赖树中
            if(!taskRuntimeInfos.containsKey(taskId)){
                throw  java.lang.RuntimeException("block task ${task.id} not in dependency tree.")
            }else{
                val task= getTaskRuntimeInfo(taskId)?.task
                traversakDependencyPriority(task)
            }
        }
    }

    private fun traversakDependencyPriority(task: Task?){
          if(task==null) return
    }
    private fun innerTraversakDependencyTreeAndInit(
        task: Task,
        traversalVisitor:LinkedHashSet<Task>
    ){
        //初始化 taskRuntimeInfo 并校验是否存在相同的任务名称 task.ID
        var taskRuntimeInfo= getTaskRuntimeInfo(task.id)
        if(taskRuntimeInfo==null){
            taskRuntimeInfo= TaskRuntimeInfo(task)
            if(blockTasksId.contains(task.id)){
                taskRuntimeInfo!!.isBlockTask=true
            }
            taskRuntimeInfos[task.id]=taskRuntimeInfo
        }else{
            if(!taskRuntimeInfo.isSameTask(task)){
                throw java.lang.RuntimeException("not allow to contain the same id ${task.id}")
            }
        }
        //校验环形依赖
        for(behindTask in task.behindTasks){
            if(!traversalVisitor.contains(behindTask)){
                traversalVisitor.add(behindTask)
            }else{
                throw  java.lang.RuntimeException("not allow loopback dependency ,task id =${task.id}")
            }
            //start --> task1 -->task2 -->task3 -->task4 -->task5 -->end
            //对 task3 后面的依赖任务路径上的task 做环形依赖检查 初始化runtimeInfo信息
            if(BuildConfig.DEBUG && behindTask.behindTasks.isEmpty()){
                //behindTask = end
                val iterator=traversalVisitor.iterator()
                val builder:StringBuilder = StringBuilder()
                while (iterator.hasNext()){
                    builder.append(iterator.next().id)
                    builder.append("-->")
                }
                Log.e(TaskRuntimeListener.TAG,builder.toString())
            }
            innerTraversakDependencyTreeAndInit(behindTask,traversalVisitor)
            traversalVisitor.remove(behindTask)
        }
    }
    fun runWaitingTasks(){
        if(hasWaitingTasks()){
            if(waitingTasks.size>1){
                Collections.sort(waitingTasks,taskComparator)
            }
            if(hasBlockTasks()){
                val head= waitingTasks.removeAt(0)
                head.run()
            }else{
                for(waitingTask in waitingTasks){
                    MainHandler.postDelay(waitingTask.delayMills,waitingTask)
                }
                waitingTasks.clear()
            }
        }
    }
}